package com.wzy.tools.utils;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.databind.type.MapType;
import lombok.SneakyThrows;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 替代fastjson的JSON类
 *
 * @author lidehua
 * @since 2019-09-06
 */
public class JSON {

    private static ObjectMapper mapper = new ObjectMapper()
            .findAndRegisterModules()
            .setSerializationInclusion(Include.NON_NULL)
            .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    private JSON() {}

    @SneakyThrows
    public static String toJSONString(Object value) {
        return mapper.writeValueAsString(value);
    }

    @SneakyThrows
    public static <T> T parseObject(String content, Class<T> clazz) {
        return mapper.readValue(content, clazz);
    }

    @SneakyThrows
    public static <T> T parseObject(String content, TypeReference<T> typeReference) {
        return mapper.readValue(content, typeReference);
    }

    @SneakyThrows
    public static <T> List<T> parseArray(String content, Class<T> clazz) {
        CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(List.class, clazz);
        return mapper.readValue(content, collectionType);
    }

    @SneakyThrows
    public static List<Map<String, Object>> parseArray(String content) {
        MapType mapType = mapper.getTypeFactory().constructMapType(HashMap.class, String.class, Object.class);
        CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(List.class, mapType);
        return mapper.readValue(content, collectionType);
    }

    @SneakyThrows
    public static <T> Map<String, T> parseMap(String content, Class<T> clazz) {
        MapType javaType = mapper.getTypeFactory().constructMapType(HashMap.class, String.class, clazz);
        return mapper.readValue(content, javaType);
    }

    @SneakyThrows
    public static Map<String, Object> parseObject(String content) {
        MapType javaType = mapper.getTypeFactory().constructMapType(HashMap.class, String.class, Object.class);
        return mapper.readValue(content, javaType);
    }

    public static <T> T toJavaObject(Object fromValue, Class<T> clazz) {
        if (fromValue == null) {
            return null;
        }
        return mapper.convertValue(fromValue, clazz);
    }

    public static <T> List<T> toJavaArrayObject(Object fromValue, Class<T> clazz) {
        if (fromValue == null) {
            return Collections.emptyList();
        }
        CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(List.class, clazz);
        return mapper.convertValue(fromValue, collectionType);
    }

    public static <T> T toJavaObject(Object fromValue, JavaType javaType) {
        if (fromValue == null) {
            return null;
        }
        return mapper.convertValue(fromValue, javaType);
    }

    public static <T> T toJavaObject(Object fromValue, TypeReference<T> typeReference) {
        if (fromValue == null) {
            return null;
        }
        return mapper.convertValue(fromValue, typeReference);
    }

    public static Map<String, Object> toObject(Object fromValue) {
        if (fromValue == null) {
            return null;
        }
        MapType javaType = mapper.getTypeFactory().constructMapType(HashMap.class, String.class, Object.class);
        return mapper.convertValue(fromValue, javaType);
    }

    public static List<Map<String, Object>> toArrayObject(Object fromValue) {
        if (fromValue == null) {
            return Collections.emptyList();
        }
        MapType mapType = mapper.getTypeFactory().constructMapType(HashMap.class, String.class, Object.class);
        CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(List.class, mapType);
        return mapper.convertValue(fromValue, collectionType);
    }

    @SneakyThrows
    public static Map<String, Object> toMap(Object obj) {
        if (null == obj) {
            return null;
        }
        MapType javaType = mapper.getTypeFactory().constructMapType(HashMap.class, String.class, Object.class);
        return mapper.readValue(JSON.toJSONString(obj), javaType);
    }

    @SneakyThrows
    public static <K, V> Map<K, V> toMap(String value, Class<K> keyClass, Class<V> valueClass) {
        MapType javaType = mapper.getTypeFactory().constructMapType(HashMap.class, keyClass, valueClass);
        return mapper.readValue(value, javaType);
    }

}
